//通常情况下，使用模板可以实现一些与类型无关的代码
//但对于一些特殊类型的可能会得到一些错误的结果
//
//此时，就需要对模板进行特化。即：在原模板类的基础上
//针对特殊类型所进行特殊化的实现方式
//模板特化中分为函数模板特化与类模板特化

//函数模板特化步骤
//1. 必须要先有一个基础的函数模板
//2. 关键字template后面接一对空的尖括号<>
//3. 函数名后跟一对尖括号，尖括号中指定需要特化的类型
//4. 函数形参表: 必须要和模板函数的基础参数类型完全相同，如果不同编译器可能会报一些奇怪的错误。

//注意:
//函数模板不支持偏特化
//只支持全特化
//类模板即支持全特化,也支持偏特化

#include <iostream>
#include <string.h>
#include <typeinfo>

using namespace std;

////函数模板
//template<class T>
//bool is_equal(const T& left, const T& right)
//{
//    return left == right;
//}
//
////函数模板全特化
////注意这里的const char* ,实际模板的形参是const char* const&
//template<>
//bool is_equal<const char* const>(const char* const& left, const char* const& right)
//{
//    if(strcmp(left, right) > 0)
//        return true;
//    return false;
//}
//
//int main()
//{
//    cout << is_equal(1, 2) << endl;
//
//    const char* p1 = "zello";
//    const char* p2 = "hello";
//    //这里需要函数模板全特化,单独进行处理
//    cout << is_equal(p1, p2) << endl;
//    return 0;
//}

//类模板

//类模板全特化:
//全特化即是将模板参数列表中所有的参数都确定化。

template<class T1, class T2>
class data 
{
public:
    data()
    {
        cout << "date<T1, T2>" << endl;
    }
private:
    T1 _d1;
    T2 _d2;
};

template<>
class data<int, char>
{
public:
    data()
    {
        cout << "data<int, char>" << endl;
    }
private:
    int _d1;
    char _d2;
};

//偏特化：任何针对模版参数进一步进行条件限制设计的特化版本。
//部分特化:将模板参数类表中的一部分参数特化。

//将第二个参数特化为int
template<class T1>
class data<T1, int>
{
public:
    data()
    {
        cout << "data<T1, int>" << endl;
    }
private:
    T1 _d1;
    int _d2;
};

//参数更进一步的限制
//偏特化并不仅仅是指特化部分参数
//而是针对模板参数更进一步的条件限制所设计出来的一个特化版本。

//将两个参数特化为指针类型
template<class T1, class T2>
class data<T1*, T2*>
{
public:
    data()
    {
        cout << "data<T1*, T2*>" << endl;
        cout << typeid(T1).name() << endl;
    }
private:
    T1* _d1;
    T2* _d2;
};

//将两个参数特化为引用类型

template<class T1, class T2>
class data<T1&, T2&>
{
public:
    data(const T1& d1, const T2& d2)
        :_d1(d1)
         ,_d2(d2)
    {
        cout << "data<T1&, T2&>" << endl;
        cout << typeid(T1&).name() << endl;
    }
private:
    const T1& _d1;
    const T2& _d2;
};

int main()
{
    data<int, double> d1;
    data<int, char> d2;
    data<int, int> d3;
    data<int*, int*> d4;
    data<int&, int&> d5(1, 2);
    return 0;
}
